//
// Created by Administrator on 2020/10/27.
//

#include "l1IntfUl.h"
#include "../../../l3Intf/include/l3IntfDef.h"

void RAN_L2_L1I_UL_PotCellProcess(S_RanL2CellInst *pCellInst)
{
    int32_t rc;
    uint32_t size;
    uint32_t needSendInd;
    S_RanCommMsgHdr *pCommMsgHdr;
    S_OsSelectInd indMsg;

    needSendInd = FALSE;
    while (1)
    {
        pCommMsgHdr = VarRB_ReadRequest(pCellInst->pL1L2CpMsgQue, &size);
        IF_BREAK(==, NULL, pCommMsgHdr, NO_LOG_MESSAGE);

        switch (pCommMsgHdr->type)
        {
        case RAN_L1_API_MSG_PARAMS_RSP:
            CSP_LOG_INF(RAN_MD_L2_L1I, "RAN_L2_L1I_UL_PotCellProcess() recv RAN_L1_API_MSG_PARAMS_RSP\n");
            VRB_PUT(rc, gpRanL2Context->pL1iL3iMsgQue, pCommMsgHdr, pCommMsgHdr->size);
            break;
        case RAN_L1_API_MSG_CONFIG_RSP:
            CSP_LOG_INF(RAN_MD_L2_L1I, "RAN_L2_L1I_UL_PotCellProcess() recv RAN_L1_API_MSG_CONFIG_RSP\n");
            VRB_PUT(rc, gpRanL2Context->pL1iL3iMsgQue, pCommMsgHdr, pCommMsgHdr->size);
            break;
        case RAN_L1_API_MSG_START_RSP:
            CSP_LOG_INF(RAN_MD_L2_L1I, "RAN_L2_L1I_UL_PotCellProcess() recv RAN_L1_API_MSG_START_RSP\n");
            VRB_PUT(rc, gpRanL2Context->pL1iL3iMsgQue, pCommMsgHdr, pCommMsgHdr->size);
            break;
        default:
            CSP_LOG_WRN(RAN_MD_L2_L1I, "RAN_L2_L1I_UL_PotCellProcess() recv unsupport msg[%#x]\n", pCommMsgHdr->type);
            break;
        }
        VarRB_ReadConsume(pCellInst->pL1L2CpMsgQue, pCommMsgHdr);
        needSendInd = TRUE;
    }
    if (needSendInd)
    {
        indMsg.ind = RAN_L2_INTRA_IND_MSG_L1_RSP_MSG;
        OS_SelectSend(&gpRanL2L3IntfContext->selector, &indMsg);
    }
}

void RAN_L2_L1I_UL_PotNodeBProcess(S_RanL2NbInst *pNbInst)
{
    uint32_t cellLoop;
    S_RanL2CellInst *pCellInst;

    for (cellLoop = 0; cellLoop < RAN_CELL_NUM_MAX; cellLoop++)
    {
        pCellInst = &pNbInst->cellInst[cellLoop];
        IF_CONTINUE(==, FALSE, pCellInst->inUse, NO_LOG_MESSAGE);
        RAN_L2_L1I_UL_PotCellProcess(pCellInst);
    }
}

void RAN_L2_L1I_UL_PotRanProcess()
{
    uint32_t nbLoop;
    S_RanL2NbInst *pNbInst;

    for (nbLoop = 0; nbLoop < RAN_NODEB_NUM_MAX; nbLoop++)
    {
        pNbInst = &gpRanL2Context->nbInst[nbLoop];
        IF_CONTINUE(==, FALSE, pNbInst->inUse, NO_LOG_MESSAGE);
        RAN_L2_L1I_UL_PotNodeBProcess(pNbInst);
    }
}

void RAN_L2_L1I_UL_PtoProcess()
{
    RAN_L2_L1I_UL_PotRanProcess();
}

void RAN_L2_L1I_UL_WakeUp(S_RanL2CellInst *pCellInst)
{
    S_OsSelectInd indMsg;

    indMsg.ind = RAN_L2_INTRA_IND_MSG_TTI_IND;
    indMsg.sn = ((uint32_t)pCellInst->currAirSfnSlot.sfn << 16) | pCellInst->currAirSfnSlot.slot;
    OS_SelectSend(&pCellInst->ulHiTtiSelector, &indMsg);
    OS_SelectSend(&pCellInst->dlHiTtiSelector, &indMsg);
    OS_SelectSend(&pCellInst->ulLoTtiSelector, &indMsg);
    OS_SelectSend(&pCellInst->mschSchTtiSelector, &indMsg);
    OS_SelectSend(&pCellInst->mschAlgTtiSelector, &indMsg);
}

void RAN_L2_L1I_UL_TtiCellProcess(S_RanL2CellInst *pCellInst)
{
    int32_t rc;
    uint32_t size;
    S_RanCommMsgHdr *pCommMsgHdr;

    while (1)
    {
        pCommMsgHdr = VarRB_ReadRequest(pCellInst->pL1L2UpMsgQue, &size);
        IF_BREAK(==, NULL, pCommMsgHdr, NO_LOG_MESSAGE);

        switch (pCommMsgHdr->type)
        {
        case RAN_L1_API_MSG_SLOT_IND:
        {
            uint32_t sfnSlot;
            S_RanL1ApiMsgSlotInd *pSlotInd;
            pSlotInd = (S_RanL1ApiMsgSlotInd *)pCommMsgHdr;
            if (pCellInst->currAirSfnSlot.sfn != pSlotInd->sfn || pCellInst->currAirSfnSlot.slot != pSlotInd->slot)
            {
                CSP_LOG_WRN(RAN_MD_L2_L1I, "RAN_L2_L1I_UL_TtiCellProcess() sfn is not coutinue! old[%u, %u], new[%u, %u]\n",
                    pCellInst->currAirSfnSlot.sfn, pCellInst->currAirSfnSlot.slot, pSlotInd->sfn, pSlotInd->slot);
            }
            pCellInst->currAirSfnSlot.sfn = pSlotInd->sfn;
            pCellInst->currAirSfnSlot.slot = pSlotInd->slot;
            O5G_SfnSlot_Add(&pCellInst->currAirSfnSlot.sfn, &pCellInst->currAirSfnSlot.slot, pCellInst->slotNum, 1);

            LOG_UpdateTick((uint64_t)pCellInst->currAirSfnSlot.sfn << 8 | pCellInst->currAirSfnSlot.slot);

//            CSP_LOG_INF(RAN_MD_L2_L1I, "RAN_L2_L1I_UL_TtiCellProcess() recv RAN_L1_API_MSG_SLOT_IND [%u, %u]\n", pSlotInd->sfn, pSlotInd->slot);

            RAN_L2_L1I_UL_WakeUp(pCellInst);
        }
            break;
        default:
            CSP_LOG_WRN(RAN_MD_L2_L1I, "RAN_L2_L1I_UL_TtiCellProcess() recv unsupport msg[%#x]\n", pCommMsgHdr->type);
            break;
        }
        VarRB_ReadConsume(pCellInst->pL1L2UpMsgQue, pCommMsgHdr);
    }
}

void RAN_L2_L1I_UL_TtiProcess(int32_t event, int fd, void *data)
{
    int32_t rc;
    S_OsSelectInd indMsg;
    S_RanL2CellInst *pCellInst;

    pCellInst = (S_RanL2CellInst *)data;

    rc = OS_SelectRecvByFd(fd, &indMsg);
    IF_RETURN(!=, O5G_RC_OK, rc, NO_RETURN_VALUE, "RAN_L2_L1I_UL_TtiProcess() OS_SelectRecv() error!\n");

    if (RAN_L1_L2_IND_MSG_TTI_INT != indMsg.ind)
    {
        CSP_LOG_WRN(RAN_MD_L3_COMM, "RAN_L2_L1I_UL_TtiProcess() recv unsupport ind[%#x]\n", indMsg.ind);
    }
    RAN_ADD_DBG_CODE(RAN_DC_L2_RECV_TTI_IND);

    RAN_L2_L1I_UL_TtiCellProcess(pCellInst);
    RAN_L2_L1I_UL_PotRanProcess();
}

void *RAN_L2_L1I_UL_Task(void* arg)
{
    int fd;
    int32_t rc;
    uint32_t nbLoop;
    uint32_t cellLoop;
    S_RanL2NbInst *pNbInst;
    S_RanL2CellInst *pCellInst;

    for (nbLoop = 0; nbLoop < RAN_NODEB_NUM_MAX; nbLoop++)
    {
        pNbInst = &gpRanL2Context->nbInst[nbLoop];
        IF_CONTINUE(==, FALSE, pNbInst->inUse, NO_LOG_MESSAGE);
        for (cellLoop = 0; cellLoop < RAN_CELL_NUM_MAX; cellLoop++)
        {
            pCellInst = &pNbInst->cellInst[cellLoop];
            IF_CONTINUE(==, FALSE, pCellInst->inUse, NO_LOG_MESSAGE);

            fd = pCellInst->ttiIntSelector.recvFd;
            POLLER_Add(gpRanL2L1IntfContext->ulPoller, fd, RAN_L2_L1I_UL_TtiProcess, NULL, NULL, pCellInst);
        }
    }

    while (1)
    {
        rc = POLLER_Poll(gpRanL2L1IntfContext->ulPoller, 10);
        if (0 == rc)
        {
            /*
             * POLL TIME OUT处理，是为了在L1 START前处理能够处理L3等消息。
             * L1 START后就会有TTI消息上来，就不会超时进入此分支。
             */
            RAN_L2_L1I_UL_PtoProcess();
        }
        pthread_testcancel();
    }
    return NULL;
}
